오픈소스 기여 방법 및 순서
회사([[[Git] 브랜치 관리 전략 (Branch Management Gu - 핵심 개념 및 특징 정리|브랜치 관리 전략]])는 GitLab 기반으로 하나의 저장소를 여러 사람이 직접 브랜치를 파서 공유하는 방식이지만, 오픈소스는 대부분 자신의 계정에 저장소를 fork(복제) 한 뒤 거기서 작업하고, upstream 원본 저장소로 PR을 보내는 방식이다. 이 차이 때문에 순서와 용어가 회사 방식과 꽤 다르다. GlueSQL에 실제로 적용한 사례는 [[[프로젝트] GlueSQL PR-이슈 작성법|GlueSQL PR-이슈 작성법]] 참고.
1. 프로젝트 파악 — 규칙부터 확인
기여를 시작하기 전에 그 프로젝트만의 관례를 먼저 읽는다. 관례를 안 지키면 코드가 맞아도 리젝될 수 있다.
- README.md: 빌드 방법, 개발 환경 요구사항
- CONTRIBUTING.md (있으면): 브랜치 네이밍, 커밋 메시지 규칙, PR 템플릿, 코드 스타일
.github/폴더: PR/이슈 템플릿(.github/PULL_REQUEST_TEMPLATE.md,.github/ISSUE_TEMPLATE/), CI 워크플로(.github/workflows/) — CI가 뭘 검사하는지 보면 PR 제출 전에 로컬에서 뭘 돌려봐야 하는지 알 수 있다.- CONTRIBUTING 문서가 없는 프로젝트도 많다. 이 경우 최근 머지된 PR/이슈 10~20개를 직접 열어서 실제 관례를 역으로 추론해야 한다 — GlueSQL이 이 경우였다(공식 CONTRIBUTING.md 없음, 커뮤니티 멘티 가이드만 존재).
- 코드 컨벤션: linter/formatter 설정 파일(
.eslintrc,rustfmt.toml,.clippy.toml등)이 있으면 그게 곧 스타일 가이드. 없으면 기존 코드 스타일을 그대로 따라간다. - 테스트 실행법:
README나 CI 워크플로 파일에서 테스트 명령어를 찾는다(예: Rust면cargo test, Node면npm test). PR 올리기 전 반드시 로컬에서 통과 확인.
2. 기여 항목 찾기 — 일반 원칙
good first issue,help wanted라벨을 먼저 확인 — 초심자를 배려해 스코프를 좁혀둔 이슈들.- 프로젝트에 “미구현 기능 추적” 성격의 트래킹 이슈가 있는지 확인 (예: GlueSQL의 #1684). 있으면 착수 후보를 고르기 가장 쉬운 곳.
- 소스코드에서 직접 미구현/제한 지점을 찾는 방법 — 언어/프로젝트마다 표현 방식이 다르다:
TODO,FIXME주석 — 가장 흔하지만 모든 프로젝트가 이렇게 표시하진 않음todo!(),unimplemented!(),NotImplementedError같은 언어별 “미구현” 매크로/예외- 에러 메시지에 “not supported”류 문자열 — GlueSQL은 이 방식(
*NotSupported에러 variant 110여 개)을 씀. 실제 조사 과정은 [[[프로젝트] GlueSQL 기여항목 찾기|GlueSQL 기여항목 찾기]] 참고 - 인터페이스/트레이트는 정의돼 있는데 구현체 일부만 실제로 구현된 경우(스텁이 기본값만 반환)
- 착수 전 반드시 담당자 유무를 확인한다 — 이슈 코멘트에 “I’ll take this” 같은 선점 표시가 있는지, 없으면 스스로 “작업 시작합니다” 코멘트를 남겨 중복 작업을 방지한다.
- 이슈 없이 바로 PR을 올려도 되는지는 프로젝트마다 다르다. 스코프가 작고 자기 완결적인 버그 수정은 대부분 허용되지만, 새 설계 판단이 들어가는 변경은 이슈로 먼저 합의를 받는 쪽이 리스크가 적다.
3. Fork 기반 워크플로 — 회사 GitLab 방식과의 차이
회사([[[Git] 브랜치 관리 전략 (Branch Management Gu - 핵심 개념 및 특징 정리|브랜치 관리 전략]])는
하나의 원격 저장소(origin)에 직접 브랜치를 만들지만, 오픈소스는 보통 두 개의 원격
저장소를 다룬다.
| 개념 | 회사(GitLab) 방식 | 오픈소스(GitHub fork) 방식 |
|---|---|---|
| 저장소 | 하나의 공유 저장소에 직접 브랜치 | 원본을 내 계정으로 fork → 내 저장소에서 작업 |
| 원격(remote) | origin 하나 | origin(내 fork) + upstream(원본) 두 개 |
| 브랜치 생성 위치 | 공유 저장소 안에서 바로 생성 | 내 fork에서 생성, 원본에는 브랜치를 만들지 않음 |
| 병합 요청 | Merge Request(MR), 팀 내 리뷰어 지정 | Pull Request(PR), 메인테이너/외부 기여자가 리뷰 |
| 최신화 | git pull | git fetch upstream → main 브랜치에 병합 후 fork에도 push |
기본 순서:
# 1. GitHub 웹에서 Fork 버튼으로 내 계정에 복제
git clone https://github.com/<내계정>/<repo>.git
cd <repo>
git remote add upstream https://github.com/<원본계정>/<repo>.git
# 2. 작업 전 항상 upstream 기준으로 최신화
git fetch upstream main
git switch main
git merge --ff-only upstream/main # 로컬 main이 upstream과 다르면 실패 → 이력이 꼬였다는 신호
git push origin main # 내 fork의 main도 최신으로 맞춤
# 3. 작업 브랜치 생성 (네이밍은 프로젝트 관례를 따름 — 소문자/하이픈 조합이 일반적)
git switch -c fix/short-description4. 로컬 개발 사이클
- 현재 동작을 먼저 재현한다. 고치기 전에 관련 테스트를 돌려보거나 최소 재현 코드/쿼리로 지금 상태를 확인 — “무엇이 바뀌었는지”를 스스로 증명할 수 있어야 한다.
- 기존 패턴을 검색해서 따라간다. 비슷한 기능이 이미 있으면 그 코드의 구조·네이밍· 테스트 스타일을 그대로 템플릿 삼는다. 새 스타일을 만들지 않는다.
- 작은 단위로 커밋한다. 하나의 커밋이 하나의 논리적 변경을 담도록 — 리뷰어가 diff를 따라가기 쉬워진다.
- 테스트를 추가/확장한다. 새 동작이나 새 에러 경로에는 반드시 테스트를 붙인다.
- PR 제출 전 로컬 검증: 프로젝트가 요구하는 linter/formatter/전체 테스트를 전부 통과시킨 뒤에 올린다(CI가 실패하면 리뷰가 밀린다).
5. 커밋/PR 제목 컨벤션 — “프로젝트마다 다르다”는 것 자체가 규칙
회사([[[Git] COMMIT 컨벤션 가이드 - 핵심 개념 및 특징 정리|COMMIT 컨벤션 가이드]])처럼
feat/fix/refactor 같은 타입 접두사를 강제하는 프로젝트(Conventional Commits 계열)도
있지만, 모든 오픈소스 프로젝트가 이 방식을 쓰는 건 아니다.
- 예: GlueSQL은 타입 접두사를 쓰지 않는다. 최근 머지 PR 30개를 직접 조사한 결과 전부(예외 1건 제외) 동사원형으로 시작하는 평서문 제목이었다 — 자세한 근거는 [[[프로젝트] GlueSQL PR-이슈 작성법|GlueSQL PR-이슈 작성법]] 0절 참고.
- 결론: “이 프로젝트가 Conventional Commits를 쓰는지”는 추측하지 말고, 최근 머지된
커밋/PR 히스토리를 직접 열어서 확인한다.
CONTRIBUTING.md에 명시돼 있으면 그것을 따르고, 없으면 최근 이력의 다수 패턴을 따른다.
6. 이슈 작성 — 일반 원칙
프로젝트마다 템플릿은 다르지만 공통적으로 요구되는 정보는 같다.
- 무엇이 문제인지 (버그면 재현 가능한 최소 예시, 기능 제안이면 왜 필요한지)
- 기대 동작과 실제 동작의 차이
- 재현 가능한 형태로 제공 — 코드/커맨드를 그대로 복붙해서 재현할 수 있게. “가끔 안 돼요” 같은 서술은 메인테이너가 판단하기 어렵다.
- 기능 제안이라면 막연한 아이디어보다 구체적 시그니처/예시 코드를 먼저 스케치해서 보여주면 메인테이너가 “이 방향이 맞다/아니다”를 빠르게 판단할 수 있다.
7. PR 작성 — 일반 원칙
GitHub 생태계에서 사실상 표준으로 자리잡은 형태:
**Summary**
- 왜 이 변경이 필요한가 (문제/동기)
- 무엇을 바꿨는가 (핵심 변경사항)
- (필요시) 왜 이 방식을 택했는가 — 대안과 트레이드오프
**Test plan**
- [x] 실행한 테스트 명령어 + 결과 (통과 개수 등, 구체적으로)
- [x] linter/formatter 통과 여부
Fixes #NNN ← 머지되면 해당 이슈가 자동으로 닫힘 (Closes/Resolves도 동일)
- PR은 작을수록 리뷰가 빠르다. 여러 관심사가 섞인 PR은 쪼개는 것이 좋다.
- 작업 중임을 알리고 피드백을 미리 받고 싶으면 Draft PR로 올린다.
Fixes/Closes/Resolves+#이슈번호키워드는 대소문자 구분 없이 동작하며, 복수 이슈도 나열 가능(Fixes #1, Fixes #2). 자동 종료 없이 그냥 참조만 걸고 싶으면 키워드 없이#N만 언급한다.
8. 리뷰 대응
- 리뷰 코멘트에 대한 수정은 기존 커밋에 fixup/추가 커밋으로 반영하고, 리뷰가 끝나기 전까지는 force-push(히스토리 재작성)를 피한다 — 리뷰어가 diff 변화를 추적하기 어려워진다. 머지 직전에 정리(squash/rebase)가 필요하면 메인테이너 안내를 따른다.
- 논의가 여러 갈래로 길어지면, 스코프를 벗어나는 부분은 별도 이슈로 분리하고 현재 PR은 원래 스코프에 집중한다.